import model.BatchModel;
import model.ConnectHandlerLineModel;
import model.DataBatchModel;
import model.IniEquipmentDateModel;
import service.ConnectHandlerTask;
import service.ToDbTask;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.ServerSocketChannel;
import java.nio.charset.Charset;
import java.util.*;

public class TCPServer implements ServerAcceptor.AcceptListener {
    private final String serverIp;
    private final int port;
    private ServerSocketChannel server;
    private ServerAcceptor serverAcceptor;
    private DispatchContext dispatchContext;
    private Map<Integer, Long> batchModelMap;

    public TCPServer(String serverIp, int port) {
        this.serverIp = serverIp;
        this.port = port;
        this.batchModelMap = new HashMap<>(255);
    }


    public boolean start() {
        try {
            InetSocketAddress inetSocketAddress;
            if (serverIp == null)
                inetSocketAddress = new InetSocketAddress(port);
            else
                inetSocketAddress = new InetSocketAddress(serverIp, port);

            // 启动Acceptor线程，梁昊：它就是selector选择器
            serverAcceptor = new ServerAcceptor(this);
            dispatchContext = new DispatchContext(serverAcceptor);
            ServerSocketChannel server = ServerSocketChannel.open();
            // 设置为非阻塞
            server.configureBlocking(false);
            // 绑定本地端口
            server.socket().bind(inetSocketAddress);
            // 注册客户端连接到达监听
            server.register(serverAcceptor.getSelector(), SelectionKey.OP_ACCEPT);
            this.server = server;
            this.serverAcceptor.start();
            dispatchContext.dispatchStart();
            System.out.println("服务器信息：" + server.getLocalAddress());

        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

    public void onNewSocketArrived(ConnectorHandler connectorHandler) {
        try {
            System.out.println(String.format("%s：%d，clientType:%d，Address:%d---上线，客户数：%d"
                    , connectorHandler.getIp()
                    , connectorHandler.getPort()
                    , connectorHandler.getClientType()
                    , connectorHandler.getCommandAddress()
                    , serverAcceptor.getSocketListCount()));
            dispatchContext.register(connectorHandler.getSocketChannel(), SelectionKey.OP_READ);
            dispatchContext.register(connectorHandler.getSocketChannel(), SelectionKey.OP_WRITE);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void SocketConnectorClose(String ipAndPort) {
        System.out.println(ipAndPort + "下线");
    }

    @Override
    public void onSocketMessageArrived(ConnectorHandler connectorHandler, ByteBuffer byteBuffer) {
        final int ByteBufferLength = byteBuffer.limit() - byteBuffer.position();
        if (ByteBufferLength > 0) {
            byte[] bytes = new byte[ByteBufferLength];
            byteBuffer.get(bytes);
            if (!IoContext.myCRCByte(bytes)) {
                System.out.println("--------------校验出错!---------------------");
                return;
            }
            byteBuffer.flip();
            final byte byteAddress = byteBuffer.get();
            switch (byteBuffer.get()) {
                case 0x03: {
                    final int equipmentNo = IoContext.unsignedByteToInt(byteAddress);//设备命令地址
                    int dataLength = byteBuffer.get();//长度
                    int channel = byteBuffer.get();//通道
                    Long batchId = this.batchModelMap.get(equipmentNo);
                    final Date date = new Date();
                    if (batchId != null) {
                        if (date.getTime() - batchId > IoContext.BatchTimeOut) {
                            batchId = date.getTime();
                            this.batchModelMap.put(equipmentNo, date.getTime());
                        }
                    } else {
                        batchId = date.getTime();
                        this.batchModelMap.put(equipmentNo, date.getTime());
                    }
                    int dataCount = dataLength / 6;
                    if (dataCount > 0) {
                        int index = 0;
                        byte[] dataByteWave = new byte[4];//波长数组
                        byte[] dataBytePower = new byte[2];//能量数组
                        List<DataBatchModel> dataBatchModels = new ArrayList<>(16);
                        IniEquipmentDateModel iniEquipmentDateModel = new IniEquipmentDateModel();
                        iniEquipmentDateModel.setIp(connectorHandler.getIp());
                        iniEquipmentDateModel.setPort(connectorHandler.getPort());
                        iniEquipmentDateModel.setAddress(equipmentNo);
                        iniEquipmentDateModel.setChannel(channel + 1);
                        iniEquipmentDateModel.setBatchId(String.valueOf(batchId));
                        iniEquipmentDateModel.setDateNow(new Date(batchId));
                        while (index < dataCount) {
                            byteBuffer.get(dataByteWave, 0, 4);
                            byteBuffer.get(dataBytePower, 0, 2);
                            final float aFloatWave = IoContext.byte2float(dataByteWave, 0);
                            final float aFloatPower = IoContext.getShort(dataBytePower, 0);
                            DataBatchModel dataBatchModel = new DataBatchModel();
                            dataBatchModel.setPowerIni(aFloatPower);
                            dataBatchModel.setWaveIni(aFloatWave);
                            if (dataBatchModel.getPowerValue() > IoContext.PowerMinValue
                                    && dataBatchModel.getPowerValue() < IoContext.PowerMaxValue
                                    && dataBatchModel.getWaveValue() > IoContext.WaveMinValue
                                    && dataBatchModel.getWaveValue() < IoContext.WaveMaxValue) {
                                dataBatchModels.add(dataBatchModel);
                            }
                            index++;
                        }
                        if (!dataBatchModels.isEmpty()) {
                            iniEquipmentDateModel.setDataBatchModels(dataBatchModels);
                            IoContext.getToDataBasePool().execute(new ToDbTask(
                                    IoContext.getSqlSession()
                                    , iniEquipmentDateModel));
                        }
                    }
                    final List<ConnectorHandler> displayChannel = this.serverAcceptor.getDisplayChannel();
                    if (displayChannel != null && !displayChannel.isEmpty()) {
                        for (ConnectorHandler handler : displayChannel) {
                            handler.writeMessage(bytes);
                        }
                    }
                }
                break;
                case 0x10://注册
                case 0x11://退出
                    connectorHandler.setClientType((byte) 1);
                    connectorHandler.writeMessage(bytes);
                    break;
                case 0x12://得到在线信息
                    //加入存入数据库的代码
                    final List<ConnectorHandler> displayChannel = this.serverAcceptor.getDisplayChannel((byte) -10);
                    if (displayChannel != null && !displayChannel.isEmpty()) {
                        ConnectHandlerLineModel[] connectHandlerLineModels = new ConnectHandlerLineModel[displayChannel.size()];
                        for (int i = 0; i < displayChannel.size(); i++) {
                            connectHandlerLineModels[i] = new ConnectHandlerLineModel(
                                    displayChannel.get(i).getIp()
                                    , displayChannel.get(i).getPort()
                                    , displayChannel.get(i).getLastWriteTime()
                                    , displayChannel.get(i).getLastReadTime()
                                    , displayChannel.get(i).getCreateTime()
                                    , displayChannel.get(i).getClientType()
                            );
                        }
                        IoContext.getToDataBasePool().execute(new ConnectHandlerTask<>(
                                IoContext.getSqlSession()
                                , connectHandlerLineModels
                                , ConnectHandlerLineModel.class
                        ));
                    }
                    displayChannel.clear();
                    connectorHandler.writeMessage(bytes);
                    break;
                default:
                    break;
            }
        }
        byteBuffer.clear();
    }

    /**
     * 关闭操作
     */
    void stop() {
        if (serverAcceptor != null) {
            serverAcceptor.exit();
        }
        dispatchContext.exit();

//        ConnectorHandler[] connectorHandlers;
//        synchronized (connectorHandlerList) {
//            connectorHandlers = connectorHandlerList.toArray(new ConnectorHandler[0]);
//            connectorHandlerList.clear();
//        }
//        for (ConnectorHandler connectorHandler : connectorHandlers) {
//            connectorHandler.exit();
//        }

        CloseUtils.close(server);
    }

}
